home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
scheme
/
boxer
/
boxer.lha
/
editor.lisp
< prev
next >
Wrap
Text File
|
1993-07-17
|
50KB
|
1,349 lines
;;; -*- Mode:lisp; Package:(BOXER GLOBAL 1000); Base:10.;Fonts:cptfont,cptfontb -*-
#||
Copyright 1985 Massachusetts Institute of Technology
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of M.I.T. not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission. M.I.T. makes no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
+-Data--+
This file is part of the | BOXER | system
+-------+
This file contains low-level code for the BOXER editor.
||#
;;;;INIT methods.
(DEFUN MAKE-UNINITIALIZED-ROW (&REST INIT-PLIST)
(INSTANTIATE-FLAVOR 'ROW (LOCF INIT-PLIST) NIL))
(DEFUN MAKE-UNINITIALIZED-BOX (&REST INIT-PLIST)
(INSTANTIATE-FLAVOR 'BOX (LOCF INIT-PLIST) NIL))
(DEFUN MAKE-INITIALIZED-ROW (&REST INIT-PLIST)
(INSTANTIATE-FLAVOR 'ROW (LOCF INIT-PLIST) T))
(DEFUN MAKE-INITIALIZED-BOX (&REST INIT-PLIST)
(INSTANTIATE-FLAVOR 'BOX (LOCF INIT-PLIST) T))
(DEFUN MAKE-INITIALIZED-GRAPHICS-BOX (&REST INIT-PLIST)
(INSTANTIATE-FLAVOR 'GRAPHICS-BOX (LOCF INIT-PLIST) T))
(DEFMETHOD (ROW :INIT) (INIT-PLIST)
(SETQ SUPERIOR-BOX (GET INIT-PLIST ':SUPERIOR-BOX)
PREVIOUS-ROW (GET INIT-PLIST ':PREVIOUS-ROW)
NEXT-ROW (GET INIT-PLIST ':NEXT-ROW)
CHAS-ARRAY (OR (GET INIT-PLIST ':CHAS-ARRAY)
(MAKE-CHAS-ARRAY))
CACHED-ELEMENTS NIL
CACHED-ENTRIES NIL))
(DEFMETHOD (DOIT-BOX :BEFORE :INIT) (INIT-PLIST)
(UNLESS (GET INIT-PLIST ':TYPE)
(PUTPROP INIT-PLIST ':DOIT-BOX ':TYPE)))
(DEFMETHOD (DATA-BOX :BEFORE :INIT) (INIT-PLIST)
(UNLESS (GET INIT-PLIST ':TYPE)
(PUTPROP INIT-PLIST ':DATA-BOX ':TYPE)))
(DEFMETHOD (BOX :INIT) (INIT-PLIST)
(SETQ ;; These we inherit from chas.
SUPERIOR-ROW (GET INIT-PLIST ':SUPERIOR-ROW)
CHA-CODE ':BOX
FONT-NO NIL
;; These come from box proper.
LOCAL-LIBRARY (GET INIT-PLIST ':LOCAL-LIBRARY)
FIRST-INFERIOR-ROW NIL
CACHED-ROWS NIL
CACHED-CODE NIL)
(WHEN (EQ 'BOX (TYPEP SELF)) ;is it a vanilla box ?, if so make it what it wants to be or
(TELL SELF :SET-TYPE (OR (GET INIT-PLIST ':TYPE) ':DOIT-BOX)))) ;else a doit box
(DEFMETHOD (LL-BOX :INIT) (INIT-PLIST)
(SETQ ;; These we inherit from chas.
SUPERIOR-ROW (GET INIT-PLIST ':SUPERIOR-ROW)
CHA-CODE ':BOX
FONT-NO NIL
;; these we inherit from vanilla boxes
FIRST-INFERIOR-ROW NIL
CACHED-ROWS NIL
CACHED-CODE NIL
STATIC-VARIABLES-ALIST (GET INIT-PLIST ':STATIC-VARIABLES-ALIST)
EXPORTS *EXPORT-ALL-VARIABLES-MARKER*))
(DEFMETHOD (GRAPHICS-BOX :INIT) (INIT-PLIST)
(SETQ ;; These we inherit from chas.
SUPERIOR-ROW (GET INIT-PLIST ':SUPERIOR-ROW)
CHA-CODE ':BOX
FONT-NO NIL
;; these we inherit from vanilla boxes
LOCAL-LIBRARY (GET INIT-PLIST ':LOCAL-LIBRARY)
FIRST-INFERIOR-ROW NIL
CACHED-ROWS NIL
CACHED-CODE NIL
STATIC-VARIABLES-ALIST (GET INIT-PLIST ':STATIC-VARIABLES-ALIST)
DISPLAY-STYLE-LIST (OR (GET INIT-PLIST ':DISPLAY-STYLE-LIST)
`(:NORMAL
,(GET INIT-PLIST ':FIXED-WID)
,(GET INIT-PLIST ':FIXED-HEI)))
;; and this is from the graphics box itself
GRAPHICS-SHEET (OR (GET INIT-PLIST ':GRAPHICS-SHEET)
(MAKE-GRAPHICS-SHEET (GET INIT-PLIST ':FIXED-WID)
(GET INIT-PLIST ':FIXED-HEI)
SELF))))
(DEFMETHOD (GRAPHICS-DATA-BOX :INIT) (INIT-PLIST)
(SETQ ;; These we inherit from chas.
SUPERIOR-ROW (GET INIT-PLIST ':SUPERIOR-ROW)
CHA-CODE ':BOX
FONT-NO NIL
;; These come from box proper.
LOCAL-LIBRARY (GET INIT-PLIST ':LOCAL-LIBRARY)
FIRST-INFERIOR-ROW NIL
CACHED-ROWS NIL
CACHED-CODE NIL
GRAPHICS-SHEET (OR (GET INIT-PLIST ':GRAPHICS-SHEET)
(MAKE-GRAPHICS-SHEET (GET INIT-PLIST ':FIXED-WID)
(GET INIT-PLIST ':FIXED-HEI)
SELF))))
(DEFMETHOD (CHA :AFTER :INIT-SELF-FROM-OLD-INSTANCE) (OLD-INSTANCE)
(LET ((SUPERIOR-CHAS-ARRAY (TELL-CHECK-NIL SUPERIOR-ROW :CHAS-ARRAY))
(OLD-CHA-NO (TELL-CHECK-NIL (TELL OLD-INSTANCE :SUPERIOR-ROW)
:CHA-CHA-NO OLD-INSTANCE)))
(WHEN (AND (NOT-NULL OLD-CHA-NO) (NOT-NULL SUPERIOR-CHAS-ARRAY))
(SETF (AREF SUPERIOR-CHAS-ARRAY OLD-CHA-NO)
(FOLLOW-STRUCTURE-FORWARDING (AREF SUPERIOR-CHAS-ARRAY OLD-CHA-NO))))))
;;; this should go into BIND sometime
(DEFUN BINDINGS-FOR-OBJECT (OBJECT BINDING-ALIST)
(SUBSET #'(LAMBDA (X) (EQ OBJECT (CDR X))) BINDING-ALIST))
(DEFMETHOD (BOX :AFTER :INIT-SELF-FROM-OLD-INSTANCE) (OLD-INSTANCE)
(DOLIST (ROW (TELL SELF :ROWS))
(TELL ROW :SET-SUPERIOR-BOX (FOLLOW-STRUCTURE-FORWARDING (TELL ROW :SUPERIOR-BOX))))
(DOLIST (BINDING (BINDINGS-FOR-OBJECT
OLD-INSTANCE
(TELL (TELL SELF :SUPERIOR-BOX) :GET-STATIC-VARIABLES-ALIST)))
(SETF (CDR BINDING) (FOLLOW-STRUCTURE-FORWARDING (CDR BINDING)))))
(defMETHOD (GRAPHICS-BOX :BEFORE :SET-FLAVOR) (new)
(tell self :erase-from-screen)
(when (eq new 'graphics-data-box)
(convert-screen-objs 'screen-box)
; (dolist (screen-obj (get-all-screen-objs self))
; (unless (eq (tell screen-obj :box-type) :port-box)
; (tell screen-obj :set-box-type ':graphics-data-box)))
(tell self :modified)))
(DEFUN-METHOD CONVERT-SCREEN-OBJS BOX (NEW-FLAVOR)
(MAPCAR #'(LAMBDA (OBJ)(TELL OBJ :SET-FLAVOR NEW-FLAVOR)
(UNLESS (PORT-BOX? (TELL OBJ :ACTUAL-OBJ))
(TELL OBJ :SET-ACTUAL-OBJ SELF)))
(GET-ALL-SCREEN-OBJS SELF)))
(defun get-visible-screen-objs (graphics-box)
(cond ((null (tell graphics-box :ports)) (tell graphics-box :displayed-screen-objs))
(t (append (tell graphics-box :displayed-screen-objs)
(loop for port in (tell graphics-box :ports)
appending (tell port :displayed-screen-objs))))))
(DEFUN GET-ALL-SCREEN-OBJS (BOX)
(cond ((null (tell box :ports)) (tell box :screen-objs))
(t (append (tell box :screen-objs)
(loop for port in (tell box :ports)
appending (tell port :screen-objs))))))
(DEFMETHOD (GRAPHICS-BOX :AFTER :INIT-SELF-FROM-OLD-INSTANCE) (IGNORE)
;; presumably all the instance variables common with ordinary boxes will have been
;; already initialized by the primary method. All we have to do is...
(CONVERT-SCREEN-OBJS 'GRAPHICS-SCREEN-BOX)
(SETQ GRAPHICS-SHEET (MAKE-GRAPHICS-SHEET (CADR DISPLAY-STYLE-LIST)
(CADDR DISPLAY-STYLE-LIST)
SELF))
(TELL SELF :MODIFIED))
(DEFMETHOD (DOIT-BOX :AFTER :INIT-SELF-FROM-OLD-INSTANCE) (IGNORE)
(CONVERT-SCREEN-OBJS 'SCREEN-BOX)
(DOLIST (ROW (TELL SELF :ROWS))
(TELL ROW :MODIFIED)))
(DEFMETHOD (DATA-BOX :AFTER :INIT-SELF-FROM-OLD-INSTANCE) (IGNORE)
(CONVERT-SCREEN-OBJS 'SCREEN-BOX)
(DOLIST (ROW (TELL SELF :ROWS))
(TELL ROW :MODIFIED)))
(DEFMETHOD (BOX :AFTER :INIT) (INIT-PLIST)
(TELL SELF :APPEND-ROW (OR (GET INIT-PLIST ':FIRST-INFERIOR-ROW)
(MAKE-INITIALIZED-ROW))))
(DEFMETHOD (BOX :SEMI-INIT) (INIT-PLIST)
(SETQ ;;these come from box proper
FIRST-INFERIOR-ROW (GET INIT-PLIST ':SUPERIOR-ROW)
CACHED-ROWS NIL
CACHED-CODE NIL
NAME (WHEN (GET INIT-PLIST :NAME)
(MAKE-NAME-ROW `(,(GET INIT-PLIST :NAME))))
DISPLAY-STYLE-LIST (OR (GET INIT-PLIST ':DISPLAY-STYLE-LIST)
DISPLAY-STYLE-LIST))
(WHEN (NAME-ROW? NAME) (TELL NAME :SET-SUPERIOR-BOX SELF))
(TELL SELF :SET-TYPE (OR (GET INIT-PLIST ':TYPE) ':DOIT-BOX)))
(DEFMETHOD (PORT-BOX :AFTER :SEMI-INIT) (INIT-PLIST)
;; might as well look to see if it is there...
(SETQ PORTS (OR (GET INIT-PLIST :PORTS) PORTS)))
(DEFMETHOD (BOX :RETURN-INIT-PLIST-FOR-FILING) ()
`(:TYPE ,(TELL SELF :TYPE)
:DISPLAY-STYLE-LIST ,DISPLAY-STYLE-LIST))
(DEFMETHOD (GRAPHICS-BOX :RETURN-INIT-PLIST-FOR-FILING) ()
`(:TYPE ,(TELL SELF :TYPE)
:DISPLAY-STYLE-LIST ,DISPLAY-STYLE-LIST
:GRAPHICS-SHEET ,GRAPHICS-SHEET))
(DEFMETHOD (BOX :RETURN-INIT-PLIST-FOR-COPY) ()
(IF (NAME-ROW? NAME)
`(:TYPE ,(TELL SELF :TYPE)
:DISPLAY-STYLE-LIST ,DISPLAY-STYLE-LIST :NAME ,(TELL SELF :NAME))
`(:TYPE ,(TELL SELF :TYPE)
:DISPLAY-STYLE-LIST ,DISPLAY-STYLE-LIST)))
;;;;PRINT-SELF methods.
(DEFMETHOD (ROW :SHOW-CHAS) ()
(FORMAT STANDARD-OUTPUT "~%")
(DOLIST (CHA (TELL SELF :CHAS))
(IF (CHA? CHA)
(FORMAT STANDARD-OUTPUT "~C" CHA)
(TELL CHA :PRINT-SELF STANDARD-OUTPUT))))
(DEFMETHOD (BOX :PRINT-SELF) (STREAM &REST IGNORE)
(FORMAT STREAM "#<~a " (TELL SELF :TYPE))
(BOX-PRINT-SELF-INTERNAL SELF STREAM)
(FORMAT STREAM " >"))
(DEFMETHOD (GRAPHICS-BOX :PRINT-SELF) (STREAM &REST IGNORE)
(FORMAT STREAM "#<~a ~a >" (TELL SELF :TYPE) (tell self :NAME)))
(DEFMETHOD (SCREEN-BOX :PRINT-SELF) (STREAM &REST IGNORE)
(FORMAT STREAM "#<SCREEN-BOX ")
(IF (GRAPHICS-BOX? ACTUAL-OBJ)
(FORMAT STREAM "~a " (TELL ACTUAL-OBJ :TYPE))
(BOX-PRINT-SELF-INTERNAL ACTUAL-OBJ STREAM))
(FORMAT STREAM " >"))
(DEFMETHOD (ROW :PRINT-SELF) (STREAM &REST IGNORE)
(FORMAT STREAM "#<ROW ")
(ROW-PRINT-SELF-INTERNAL SELF STREAM)
(FORMAT STREAM " >"))
(DEFMETHOD (NAME-ROW :PRINT-SELF) (STREAM &REST IGNORE)
(FORMAT STREAM "#<NAME-ROW ")
(ROW-PRINT-SELF-INTERNAL SELF STREAM)
(FORMAT STREAM " >"))
(DEFUN CHA-PRINT-SELF-INTERNAL (CHA STREAM)
(COND ((BOX? CHA)
(FORMAT STREAM "[]"))
(T
(FORMAT STREAM "~C" (CHA-CODE CHA)))))
(DEFUN ROW-PRINT-SELF-INTERNAL (ROW STREAM)
(PROG ()
(DO-ROW-CHAS ((CHA ROW)
(CHA-NO 0 (+ CHA-NO 1)))
(COND ((> CHA-NO 5)
(FORMAT STREAM "...")
(RETURN))
(T
(CHA-PRINT-SELF-INTERNAL CHA STREAM))))))
(DEFUN BOX-PRINT-SELF-INTERNAL (BOX STREAM)
(LET ((FIRST-ROW (TELL BOX :ROW-AT-ROW-NO 0)))
(COND ((NULL FIRST-ROW))
(T
(ROW-PRINT-SELF-INTERNAL FIRST-ROW STREAM)))))
;;keep these around for boxes to use...
(DEFGET-METHODS ((CHA :SUPERIOR-ROW) :SUPERIOR-OBJ) SUPERIOR-ROW)
(DEFSET-METHODS ((CHA :SET-SUPERIOR-ROW) :SET-SUPERIOR-OBJ) SUPERIOR-ROW)
(DEFMETHOD (CHA :SUPERIOR-BOX) ()
(TELL SUPERIOR-ROW :SUPERIOR-BOX))
;;;;USEFUL-MAPPING-FUNCTIONS
(DEFUN MAP-OVER-ALL-INFERIOR-BOXES (SUPERIOR-BOX FUNCTION)
(DO ((ROW (TELL SUPERIOR-BOX :FIRST-INFERIOR-ROW) (TELL ROW :NEXT-ROW)))
((NULL ROW))
(DO* ((CHA-NO 0 (+ CHA-NO 1))
(CHA (TELL ROW :CHA-AT-CHA-NO CHA-NO) (TELL ROW :CHA-AT-CHA-NO CHA-NO)))
((NULL CHA))
(COND ((BOX? CHA)
(FUNCALL FUNCTION CHA)
(MAP-OVER-ALL-INFERIOR-BOXES CHA FUNCTION))))))
(DEFUN MAP-OVER-INFERIOR-BOXES (SUPERIOR-BOX FUNCTION)
(DOLIST (ROW (TELL SUPERIOR-BOX :ROWS))
(DOLIST (CHA (TELL ROW :CHAS))
(WHEN (BOX? CHA)
(FUNCALL FUNCTION CHA)))))
(DEFMETHOD (BOX :MODIFIED) (&OPTIONAL (DECACHE T))
(WHEN (NOT-NULL DECACHE)
(SETQ CACHED-ROWS NIL
CACHED-CODE NIL)
(TELL SELF :PUTPROP NIL 'CACHED-BUILD))
(TELL-CHECK-NIL (TELL SELF :SUPERIOR-ROW) :MODIFIED))
(DEFMETHOD (ROW :MODIFIED) (&OPTIONAL (DECACHE T))
(WHEN (NOT-NULL DECACHE)
(SETQ CACHED-CHAS NIL
CACHED-ENTRIES NIL
CACHED-ELEMENTS NIL
CACHED-ITEMS NIL
CACHED? NIL))
(TELL-CHECK-NIL (TELL SELF :SUPERIOR-BOX) :MODIFIED T))
;;;;INCREMENT and SET-TYPE
(DEFVAR *TOGGLING-BOX-TYPES* `(:DOIT-BOX :DATA-BOX)
"This is a circular list of the different possible types of boxes.
The list is circular to make it easy to define a next type for
each type, this is used by (:method box :increment-type).")
(DEFUN TOGGLING-BOX-TYPES-NEXT-BOX-TYPE (OLD-TYPE)
(LET ((POS (FIND-POSITION-IN-LIST OLD-TYPE *TOGGLING-BOX-TYPES*))
(LEN (LENGTH *TOGGLING-BOX-TYPES*)))
(COND ((NULL POS) (CAR *TOGGLING-BOX-TYPES*))
(T (NTH (REMAINDER (+ POS 1) LEN) *TOGGLING-BOX-TYPES*)))))
(DEFMETHOD (LL-BOX :TOGGLE-TYPE) ()
(BEEP))
(DEFMETHOD (DOIT-BOX :TYPE) ()
':DOIT-BOX)
(DEFMETHOD (DATA-BOX :TYPE) ()
':DATA-BOX)
(DEFMETHOD (LL-BOX :TYPE) ()
':LL-BOX)
(DEFMETHOD (PORT-BOX :TYPE) ()
':PORT-BOX)
(DEFMETHOD (GRAPHICS-BOX :TYPE) ()
':GRAPHICS-BOX)
(DEFMETHOD (INPUT-BOX :TYPE) ()
':INPUT-BOX)
(DEFMETHOD (BOX :SET-TYPE) (NEW-TYPE)
(SELECTQ NEW-TYPE
((:DOIT-BOX DOIT-BOX)
(TELL SELF :SET-FLAVOR 'DOIT-BOX))
((:DATA-BOX DATA-BOX)
(TELL SELF :SET-FLAVOR 'DATA-BOX))
((:PORT-BOX PORT-BOX)
(TELL SELF :SET-FLAVOR 'PORT-BOX))
((:LL-BOX LL-BOX)
(TELL SELF :SET-FLAVOR 'LL-BOX))
((:GRAPHICS-BOX GRAPHICS-BOX)
(TELL SELF :SET-FLAVOR 'GRAPHICS-BOX))
((:graphics-data-box graphics-data-box)
(tell self :set-flavor 'graphics-data-box))
((:sprite-box sprite-box)
(tell self :set-flavor 'sprite-box))
((:INPUT-BOX INPUT-BOX)
(TELL SELF :SET-FLAVOR 'INPUT-BOX))
(OTHERWISE (FERROR "can't set ~s to ~s"SELF NEW-TYPE)))
(TELL SELF :MODIFIED))
(DEFMETHOD (BOX :TOGGLE-TYPE) ()
(TELL SELF :SET-TYPE (TOGGLING-BOX-TYPES-NEXT-BOX-TYPE (TELL SELF :TYPE))))
(DEFMETHOD (GRAPHICS-BOX :TOGGLE-TYPE) ()
(TELL SELF :SET-TYPE 'GRAPHICS-DATA-BOX))
(DEFMETHOD (GRAPHICS-DATA-BOX :TOGGLE-TYPE) ()
(IF (EQ SELF (OUTERMOST-BOX)) (BEEP)
(TELL SELF :SET-TYPE 'GRAPHICS-BOX)))
;;;; PORTS.
(DEFMETHOD (PORT-BOX :SET-PORT-TO-BOX) (NEW-VALUE)
(TELL NEW-VALUE :ADD-PORT SELF)
(SETQ PORTS NEW-VALUE))
(DEFMETHOD (BOX :ADD-PORT) (PORT-TO-ADD)
(UNLESS (MEMQ PORT-TO-ADD PORTS)
(PUSH PORT-TO-ADD PORTS)))
(DEFMETHOD (PORT-BOX :ADD-PORT) (PORT-TO-ADD)
(TELL PORTS :ADD-PORT PORT-TO-ADD))
(DEFMETHOD (BOX :REMOVE-PORT) (PORT-TO-DELETE)
(SETQ PORTS (DELQ PORT-TO-DELETE PORTS)))
;; what happens when a port's target is removed from the hierarchy ?
;; This is just a stub until we decide what to do. Old proposal to mark the port as "broken"
;; needs some redisplay hacking
(DEFMETHOD (PORT-BOX :TARGET-HAS-BEEN-DELETED-HANDLER) ()
)
;; Another stub
(DEFMETHOD (PORT-BOX :TARGET-HAS-BEEN-INSERTED-HANDLER) (TARGET)
TARGET)
;; Doesn't create the back pointer so that the port can eventually be GC'd
;; ports which use this should NEVER, NEVER, NEVER be inserted into the editor
(DEFMETHOD (PORT-BOX :SET-PORT-TO-BOX-FOR-EVAL) (NEW-VALUE)
(SETQ PORTS NEW-VALUE))
(DEFMETHOD (PORT-BOX :FIRST-INFERIOR-ROW) ()
(TELL-CHECK-NIL PORTS :FIRST-INFERIOR-ROW))
(DEFMETHOD (PORT-BOX :FIRST-INFERIOR-OBJ) ()
(TELL-CHECK-NIL PORTS :FIRST-INFERIOR-OBJ))
(DEFMETHOD (PORT-BOX :ROW-AT-ROW-NO) (ROW-NO)
(TELL-CHECK-NIL PORTS :ROW-AT-ROW-NO ROW-NO))
(DEFMETHOD (PORT-BOX :TICK) ()
(MAX (TELL-CHECK-NIL PORTS :TICK) TICK))
(DEFWHOPPER (BOX :MODIFIED) (&OPTIONAL (DECACHE T))
(CONTINUE-WHOPPER DECACHE)
(IF (LISTP PORTS)
(DOLIST (PORT PORTS)
(TELL PORT :MODIFIED DECACHE))))
;;; These are needed to handle :MODIFIED for circular structures
(DEFVAR *PORTS-ALREADY-MODIFIED* NIL)
(DEFWHOPPER (PORT-BOX :MODIFIED) (&OPTIONAL (DECACHE T))
(UNLESS (MEMQ SELF *PORTS-ALREADY-MODIFIED*)
(LET ((*PORTS-ALREADY-MODIFIED* (APPEND *PORTS-ALREADY-MODIFIED* (NCONS SELF))))
(CONTINUE-WHOPPER DECACHE))))
(DEFMETHOD (BOX :CLEAR-PORTS)()
;; for debugging
(SETQ PORTS NIL))
(DEFMETHOD (BOX :PORTS) ()
PORTS)
(DEFMETHOD (PORT-BOX :GRAPHICS-SHEET) ()
(TELL-CHECK-NIL PORTS :GRAPHICS-SHEET))
(DEFMETHOD (PORT-BOX :BIT-ARRAY-WID) ()
(TELL-CHECK-NIL PORTS :BIT-ARRAY-WID))
(DEFMETHOD (PORT-BOX :BIT-ARRAY-HEI) ()
(TELL-CHECK-NIL PORTS :BIT-ARRAY-HEI))
(DEFMETHOD (PORT-BOX :GRAPHICS-SHEET-SIZE) ()
(TELL-CHECK-NIL PORTS :GRAPHICS-SHEET-SIZE))
(DEFMETHOD (PORT-BOX :TOGGLE-TYPE) ()
(TELL-CHECK-NIL PORTS :TOGGLE-TYPE))
(DEFMETHOD (PORT-BOX :SET-TYPE) (TYPE)
(TELL-CHECK-NIL PORTS :SET-TYPE TYPE))
(COMMENT ;flush as soon as fasdumper works
;;;true names are given to boxes which are being ported to and are only assigned
;;;when a box merits one {which is at port creation time}. If the port is
;;;streamified, then the true name is stored in the port-stream and both the
;;;true name and the box it refers to are stored in a hash table, the...
;;;...*port-hash-table*
(DEFMETHOD (BOX :SET-TRUE-NAME) (NEW-NAME)
(WHEN (NULL TRUE-NAME)
(SETQ TRUE-NAME NEW-NAME)
(INTERN NEW-NAME 'BOXER)))
(DEFMETHOD (BOX :TRUE-NAME) ()
TRUE-NAME)
(DEFMETHOD (BOX :CHANGE-TRUE-NAME) ()
(LET ((NEW-TRUE-NAME (GENSYM)))
(INTERN NEW-TRUE-NAME 'BOXER)
(SETQ TRUE-NAME NEW-TRUE-NAME)))
) ;end of comment
;;; Keeping track of Ports and their targets
(DEFMETHOD (BOX :APPEND-INFERIOR-PORTS) (NEW-PORTS)
(IF (LISTP NEW-PORTS) (SETQ INFERIOR-PORTS (CL:DELETE-DUPLICATES
(APPEND INFERIOR-PORTS NEW-PORTS)))
(UNLESS (MEMQ NEW-PORTS INFERIOR-PORTS)
(SETQ INFERIOR-PORTS (APPEND INFERIOR-PORTS (NCONS NEW-PORTS)))))
(TELL-CHECK-NIL (TELL SELF :SUPERIOR-BOX) :APPEND-INFERIOR-PORTS NEW-PORTS))
(DEFMETHOD (BOX :REMOVE-INFERIOR-PORTS) (OLD-PORTS)
(IF (LISTP OLD-PORTS) (SETQ INFERIOR-PORTS (CL:SET-DIFFERENCE INFERIOR-PORTS OLD-PORTS))
(SETQ INFERIOR-PORTS (DELQ OLD-PORTS INFERIOR-PORTS)))
(TELL-CHECK-NIL (TELL SELF :SUPERIOR-BOX) :REMOVE-INFERIOR-PORTS OLD-PORTS))
(DEFMETHOD (BOX :APPEND-INFERIOR-TARGETS) (NEW-TARGETS)
(IF (LISTP NEW-TARGETS) (SETQ INFERIOR-TARGETS (CL:DELETE-DUPLICATES
(APPEND INFERIOR-TARGETS NEW-TARGETS)))
(UNLESS (MEMQ NEW-TARGETS INFERIOR-TARGETS)
(SETQ INFERIOR-TARGETS (APPEND INFERIOR-TARGETS (NCONS NEW-TARGETS)))))
(TELL-CHECK-NIL (TELL SELF :SUPERIOR-BOX) :APPEND-INFERIOR-TARGETS NEW-TARGETS))
(DEFMETHOD (BOX :REMOVE-INFERIOR-TARGETS) (OLD-TARGETS)
(IF (LISTP OLD-TARGETS) (SETQ INFERIOR-TARGETS
(CL:SET-DIFFERENCE INFERIOR-TARGETS OLD-TARGETS))
(SETQ INFERIOR-TARGETS (DELQ OLD-TARGETS INFERIOR-TARGETS)))
(TELL-CHECK-NIL (TELL SELF :SUPERIOR-BOX) :REMOVE-INFERIOR-TARGETS OLD-TARGETS))
;;; in/out of the editor hierarchy
;;; Every Box needs to hack the namespace and the deallocation of screen objs
(DEFMETHOD (BOX :DELETE-SELF-ACTION) ()
(LET ((SUPERIOR-BOX (TELL SELF :SUPERIOR-BOX)))
(SETQ SCREEN-OBJS NIL)
;; update inferior port information
(UNLESS (NULL INFERIOR-PORTS)
(DOLIST (INFERIOR-PORT INFERIOR-PORTS)
(TELL (TELL INFERIOR-PORT :PORTS) :REMOVE-PORT INFERIOR-PORT))
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-INFERIOR-PORTS INFERIOR-PORTS))
;; update inferior target information
(COND ((AND (NULL INFERIOR-TARGETS) (NULL PORTS)))
((NULL PORTS)
(DOLIST (INFERIOR-TARGET INFERIOR-TARGETS)
(DOLIST (P (TELL INFERIOR-TARGET :PORTS))
(TELL P :TARGET-HAS-BEEN-DELETED-HANDLER)))
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-INFERIOR-TARGETS INFERIOR-TARGETS))
((NULL INFERIOR-TARGETS)
(DOLIST (P PORTS)
(TELL P :TARGET-HAS-BEEN-DELETED-HANDLER))
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-INFERIOR-TARGETS SELF))
(T
(DOLIST (INFERIOR-TARGET INFERIOR-TARGETS)
(DOLIST (P (TELL INFERIOR-TARGET :PORTS))
(TELL P :TARGET-HAS-BEEN-DELETED-HANDLER)))
(DOLIST (P PORTS)
(TELL P :TARGET-HAS-BEEN-DELETED-HANDLER))
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-INFERIOR-TARGETS
(LIST* SELF INFERIOR-TARGETS))))
;; update the namespace
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-ALL-STATIC-BINDINGS SELF)))
(DEFMETHOD (PORT-BOX :DELETE-SELF-ACTION) ()
(LET ((SUPERIOR-BOX (TELL SELF :SUPERIOR-BOX)))
(SETQ SCREEN-OBJS NIL)
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-ALL-STATIC-BINDINGS SELF)
(TELL-CHECK-NIL SUPERIOR-BOX :REMOVE-INFERIOR-PORTS SELF)
(TELL PORTS :REMOVE-PORT SELF)
(WHEN (NULL (TELL PORTS :PORTS))
;; if the target has run out of ports, then inform its superior
(TELL-CHECK-NIL (TELL PORTS :SUPERIOR-BOX) :REMOVE-INFERIOR-TARGETS PORTS))))
(DEFMETHOD (BOX :INSERT-SELF-ACTION) ()
(LET ((SUPERIOR-BOX (TELL SELF :SUPERIOR-BOX)))
(COND-EVERY ((NAME-ROW? NAME)
(TELL NAME :UPDATE-BINDINGS T))
((NOT-NULL EXPORTS)
(TELL-CHECK-NIL SUPERIOR-BOX
:ADD-STATIC-VARIABLE-PAIR *EXPORTING-BOX-MARKER* SELF)))
;; update the inferior port information
(UNLESS (NULL INFERIOR-PORTS)
(DOLIST (INFERIOR-PORT INFERIOR-PORTS)
(TELL (TELL INFERIOR-PORT :PORTS) :ADD-PORT INFERIOR-PORT))
(TELL-CHECK-NIL SUPERIOR-BOX :APPEND-INFERIOR-PORTS INFERIOR-PORTS))
;; update the inferior target information
(COND ((AND (NULL INFERIOR-TARGETS) (NULL PORTS)))
((NULL PORTS)
(DOLIST (INFERIOR-TARGET INFERIOR-TARGETS)
(DOLIST (P (TELL INFERIOR-TARGET :PORTS))
(TELL P :TARGET-HAS-BEEN-INSERTED-HANDLER INFERIOR-TARGET)))
(TELL-CHECK-NIL SUPERIOR-BOX :APPEND-INFERIOR-TARGETS INFERIOR-TARGETS))
((NULL INFERIOR-TARGETS)
(DOLIST (P PORTS)
(TELL P :TARGET-HAS-BEEN-INSERTED-HANDLER SELF))
(TELL-CHECK-NIL SUPERIOR-BOX :APPEND-INFERIOR-TARGETS SELF))
(T
(DOLIST (INFERIOR-TARGET INFERIOR-TARGETS)
(DOLIST (P (TELL INFERIOR-TARGET :PORTS))
(TELL P :TARGET-HAS-BEEN-INSERTED-HANDLER INFERIOR-TARGET)))
(DOLIST (P PORTS)
(TELL P :TARGET-HAS-BEEN-INSERTED-HANDLER SELF))
(TELL-CHECK-NIL SUPERIOR-BOX :APPEND-INFERIOR-TARGETS
(LIST* SELF INFERIOR-TARGETS))))))
(DEFMETHOD (PORT-BOX :INSERT-SELF-ACTION) ()
(LET ((SUPERIOR-BOX (TELL SELF :SUPERIOR-BOX)))
(COND-EVERY ((NAME-ROW? NAME)
(TELL NAME :UPDATE-BINDINGS T))
((NOT-NULL EXPORTS)
(TELL-CHECK-NIL SUPERIOR-BOX
:ADD-STATIC-VARIABLE-PAIR *EXPORTING-BOX-MARKER* SELF)))
(TELL-CHECK-NIL SUPERIOR-BOX :APPEND-INFERIOR-PORTS SELF)
;; The inferior target information is handled here because this is the point where we can
;; be absolutely sure that the port has been inserted/deleted from the hierarchy.
;; Otherwise ABORT in the middle of port creation would result in a spurious target entry
(TELL-CHECK-NIL PORTS :ADD-PORT SELF)
(TELL-CHECK-NIL (TELL-CHECK-NIL PORTS :SUPERIOR-BOX) :APPEND-INFERIOR-TARGETS PORTS)))
(DEFMETHOD (LL-BOX :DELETE-SELF-ACTION) ()
;; we don't want to remove the local library from the environment structure
NIL)
(DEFMETHOD (LL-BOX :INSERT-SELF-ACTION) ()
NIL)
(DEFUN GET-BOX-NAME (NAME-ROW)
(IF (ROW? NAME-ROW)
(LET ((ROW-ENTRIES (TELL NAME-ROW :ENTRIES)))
(COND ((NULL ROW-ENTRIES) NIL)
(T (INTERN
(LOOP WITH NAME = ""
FOR ENTRY IN ROW-ENTRIES
IF (EQ ENTRY (CAR ROW-ENTRIES))
DO (SETQ NAME (STRING ENTRY))
ELSE
DO (SETQ NAME (STRING-APPEND NAME (FORMAT NIL "_~A" ENTRY)))
FINALLY
(RETURN NAME))
PKG-BU-PACKAGE))))
NIL))
(DEFUN MAKE-NAME-ROW (STUFF &OPTIONAL (CACHED-NAME NIL))
(COND ((ROW? STUFF)
STUFF)
(T
(LET ((ROW-STREAM (MAKE-ROW-STREAM `(:ROW . ,STUFF)))
(NEW-ROW (MAKE-INSTANCE 'NAME-ROW ':CACHED-NAME CACHED-NAME)))
(TELL NEW-ROW :SET-CONTENTS-FROM-STREAM ROW-STREAM NIL)
NEW-ROW))))
(DEFMETHOD (NAME-ROW :AFTER :MODIFIED) (&REST IGNORE)
;(TELL SELF :UPDATE-BINDINGS)
(DOLIST (ROW (TELL SUPERIOR-BOX :ROWS))
(TELL ROW :MODIFIED)))
(DEFMETHOD (BOX :NAME-ROW) ()
(WHEN (NAME-ROW? NAME)
NAME))
(DEFMETHOD (BOX :MAKE-NAME-ROW) ()
(LET ((NAME-ROW (MAKE-INSTANCE 'NAME-ROW)))
(SETQ NAME NAME-ROW)
(TELL NAME-ROW :SET-SUPERIOR-BOX SELF)))
;;;; BP's
(DEFUN SET-BP-ROW (BP NEW-ROW)
(CHECK-BP-ARG BP)
(CHECK-ROW-ARG NEW-ROW)
(LET ((OLD-ROW (BP-ROW BP)))
(UNLESS (EQ OLD-ROW NEW-ROW)
(SETF (%BP-ROW BP) NEW-ROW)
(SETF (ROW-BPS OLD-ROW) (DELQ BP (ROW-BPS OLD-ROW)))
(SETF (ROW-BPS NEW-ROW) (CONS BP (ROW-BPS NEW-ROW))))))
(DEFUN SET-BP-CHA-NO (BP NEW-CHA-NO)
(CHECK-ARG NEW-CHA-NO 'NUMBERP "A number")
(SETF (%BP-CHA-NO BP) NEW-CHA-NO))
(DEFUN SET-BP-SCREEN-BOX (BP NEW-SCREEN-BOX)
(CHECK-BP-ARG BP)
(OR (NULL NEW-SCREEN-BOX) (CHECK-SCREEN-BOX-ARG NEW-SCREEN-BOX))
(LET ((OLD-SCREEN-BOX (BP-SCREEN-BOX BP)))
(UNLESS (EQ OLD-SCREEN-BOX NEW-SCREEN-BOX)
(SETF (%BP-SCREEN-BOX BP) NEW-SCREEN-BOX)
(TELL OLD-SCREEN-BOX :DELETE-BP BP)
(TELL NEW-SCREEN-BOX :ADD-BP BP))))
(DEFUN SET-BP-FROM-BP (BP FROM-BP &OPTIONAL (SCREEN-BOX-TOO? T))
"Changes the first BP to point to the same place as the second BP without changing
the type. "
(CHECK-BP-ARG BP)
(CHECK-BP-ARG FROM-BP)
(SET-BP-CHA-NO BP (BP-CHA-NO FROM-BP))
(SET-BP-ROW BP (BP-ROW FROM-BP))
(WHEN SCREEN-BOX-TOO?
(SET-BP-SCREEN-BOX BP (BP-SCREEN-BOX FROM-BP))))
(DEFUN SET-BP-TYPE (BP NEW-TYPE)
(COND ((MEMQ NEW-TYPE '(:MOVING :FIXED))
(SETF (%BP-TYPE BP) NEW-TYPE))
(T
(FERROR "~S is an illegal type for a BP."))))
;;; This is useful. Note that setting a BP's Box doesn't make any sense.
(DEFUN BP-BOX (BP)
(TELL (BP-ROW BP) :SUPERIOR-BOX))
;;; Comparing BP's. BP-> returns T if <BP1> is farther along in the buffer than <BP2>.
;;; Note that farther along is defined in a top-to-bottom left-to-right sense and that depth
;;; is ignored since the function traverses upward into the lowest common superior box before
;;; doing the compare
;; Both rows are assumed to be in the same box.
(DEFUN ROW-> (ROW1 ROW2 &OPTIONAL (BOX (TELL ROW1 :SUPERIOR-BOX)))
(LOOP FOR ROW = (TELL BOX :FIRST-INFERIOR-ROW) THEN (TELL ROW :NEXT-ROW)
UNTIL (NULL ROW)
WHEN (EQ ROW ROW1)
RETURN NIL
WHEN (EQ ROW ROW2)
RETURN T))
(DEFUN ROW-< (ROW1 ROW2 &OPTIONAL (BOX (TELL ROW1 :SUPERIOR-BOX)))
(LOOP FOR ROW = (TELL BOX :FIRST-INFERIOR-ROW) THEN (TELL ROW :NEXT-ROW)
UNTIL (NULL ROW)
WHEN (EQ ROW ROW2)
RETURN NIL
WHEN (EQ ROW ROW1)
RETURN T))
;; this assumes that the BP's are in the same box and have already been decoded
;; into ROWs and CHA-NOs and returns T if the BP represented by ROW1, CHA-NO1 come FIRST
(DEFSUBST BP-COMPARE-INTERNAL-SIMPLE (ROW1 ROW2 CHA-NO1 CHA-NO2)
(COND ((AND (EQ ROW1 ROW2) (= CHA-NO1 CHA-NO2)) :EQUAL)
((AND (EQ ROW1 ROW2) (< CHA-NO1 CHA-NO2)) T)
((EQ ROW1 ROW2) NIL)
((ROW-< ROW1 ROW2) T)
(T NIL)))
;; this gets used ONLY IF the BP's aren't in the same box
;; returns the BP which occurs FIRST
;; since we are doing all this marching up and down in box structure, we might as well also
;; throw back the top level box which is inferior to the lowest common superior for each BP
;; so that other functions won't have to do all this work
;; The order of the values reurned are 1) Leading BP. 2) Leading box. 3) Trailing Box
(DEFSUBST BP-COMPARE-INTERNAL-HAIRY (BP1 BP2 ROW1 ROW2 BOX1 BOX2)
(MULTIPLE-VALUE-BIND (TOP12 PATH12)
(FIND-PATH BOX1 BOX2)
(MULTIPLE-VALUE-BIND (TOP21 PATH21)
(FIND-PATH BOX2 BOX1)
(LET ((APPARENT-ROW1 (TELL-CHECK-NIL (CAR PATH21) :SUPERIOR-ROW))
(APPARENT-ROW2 (TELL-CHECK-NIL (CAR PATH12) :SUPERIOR-ROW)))
(COND ((AND (NULL TOP12) ;BP2 is in some inferior of BOX1
(BP-COMPARE-INTERNAL-SIMPLE
ROW1 APPARENT-ROW2
(BP-CHA-NO BP1) (TELL APPARENT-ROW2 :CHA-CHA-NO (CAR PATH12))))
(VALUES BP1 (CAR PATH21) (CAR PATH12)))
((NULL TOP12)
(VALUES BP2 (CAR PATH12) (CAR PATH21)))
((AND (NULL TOP21) ;BP1 is in some inferior of BOX2 and
(EQ :EQUAL ;
(BP-COMPARE-INTERNAL-SIMPLE
APPARENT-ROW1 ROW2
(TELL APPARENT-ROW1 :CHA-CHA-NO (CAR PATH21)) (BP-CHA-NO BP2))))
(VALUES BP2 (CAR PATH12) (CAR PATH21)))
((AND (NULL TOP21) ;BP1 is in some inferior of BOX2
(BP-COMPARE-INTERNAL-SIMPLE
APPARENT-ROW1 ROW2
(TELL APPARENT-ROW1 :CHA-CHA-NO (CAR PATH21)) (BP-CHA-NO BP2)))
(VALUES BP1 (CAR PATH21) (CAR PATH12)))
((NULL TOP21)
(VALUES BP2 (CAR PATH12) (CAR PATH21)))
;; neither box is contained in the other
((BP-COMPARE-INTERNAL-SIMPLE
APPARENT-ROW1 APPARENT-ROW2
(TELL APPARENT-ROW1 :CHA-CHA-NO (CAR PATH21))
(TELL APPARENT-ROW2 :CHA-CHA-NO (CAR PATH12)))
(VALUES BP1 (CAR PATH21) (CAR PATH12)))
(T (VALUES BP2 (CAR PATH12) (CAR PATH21))))))))
(DEFUN BP-COMPARE (BP1 BP2)
"returns the BP which occurs FIRST. If they are in the same place, the first one
is returned. If they are on different levels, and the superior BP points to the
Box which contains the lower BP, then the superior BP is returned. "
(LET ((ROW1 (BP-ROW BP1)) (BOX1 (BP-BOX BP1))
(ROW2 (BP-ROW BP2)) (BOX2 (BP-BOX BP2)))
(COND ((AND (EQ BOX1 BOX2)
(BP-COMPARE-INTERNAL-SIMPLE ROW1 ROW2 (BP-CHA-NO BP1) (BP-CHA-NO BP2)))
BP1)
((EQ BOX1 BOX2) BP2)
;; so much for the simple cases, it looks like we have to do some work
(T (BP-COMPARE-INTERNAL-HAIRY BP1 BP2 ROW1 ROW2 BOX1 BOX2)))))
(DEFUN BP-< (BP1 BP2)
(IF (EQ BP2 (BP-COMPARE BP1 BP2)) NIL T))
(DEFUN BP-> (BP1 BP2)
(IF (EQ BP1 (BP-COMPARE BP1 BP2)) NIL T))
(DEFUN BP-= (BP1 BP2)
(AND (EQ (BP-ROW BP1) (BP-ROW BP2))
(= (BP-CHA-NO BP1) (BP-CHA-NO BP2))))
;;; These two functions take two BP's and return two BP's which are ordered according to
;;; location in the BUFFER and are guaranteed to be at the same level i.e. corresponding
;;; to rows in the same BOX. Note that when the second BP is in a subbox, the returned
;;; second BP's CHA-NO will be one greater than the Box's own CHA-NO so that the Box itself
;;; will be included in the specified region.
;;; Note that ORDER-BPS creates new BP's to return so we don't have to worry about accidently
;;; mutating something like the *POINT*
(DEFUN ORDER-BPS (BP1 BP2)
(LET ((START-BP (MAKE-BP :FIXED))
(STOP-BP (MAKE-BP :FIXED)))
(MULTIPLE-VALUE-BIND (FIRST-BP FIRST-BOX LAST-BOX)
(BP-COMPARE BP1 BP2)
(COND ((AND (NULL FIRST-BOX) (NULL LAST-BOX) ;both BPs are at the same level
(EQ FIRST-BP BP1)) ;and are ordered correctly
(MOVE-BP START-BP (BP-VALUES BP1)) ;place the BP's to be returned in the
(MOVE-BP STOP-BP (BP-VALUES BP2)) ;right places
(VALUES START-BP STOP-BP))
((AND (NULL FIRST-BOX) (NULL LAST-BOX))
(MOVE-BP START-BP (BP-VALUES BP2))
(MOVE-BP STOP-BP (BP-VALUES BP1))
(VALUES START-BP STOP-BP))
;; looks like the BPs are in different boxes
;; first we look for the case where on BP's box is inside the other one's
((AND (NULL FIRST-BOX) (EQ FIRST-BP BP1)) ;the leading BP is at the right level
(MOVE-BP START-BP (BP-VALUES BP1))
(MOVE-BP STOP-BP (BOX-SELF-BP-VALUES LAST-BOX)) ;point to where the box is
(SET-BP-CHA-NO STOP-BP (1+ (BP-CHA-NO STOP-BP))) ;include the box itself
(VALUES START-BP STOP-BP))
((NULL FIRST-BOX)
(MOVE-BP START-BP (BP-VALUES BP2))
(MOVE-BP STOP-BP (BOX-SELF-BP-VALUES LAST-BOX)) ;point to where the box is
(SET-BP-CHA-NO STOP-BP (1+ (BP-CHA-NO STOP-BP))) ;include the box itself
(VALUES START-BP STOP-BP))
((AND (NULL LAST-BOX) (EQ FIRST-BP BP1)) ;the trailing BP is at the right level
(MOVE-BP START-BP (BOX-SELF-BP-VALUES FIRST-BOX))
(MOVE-BP STOP-BP (BP-VALUES BP2))
(VALUES START-BP STOP-BP))
((NULL LAST-BOX)
(MOVE-BP START-BP (BOX-SELF-BP-VALUES FIRST-BOX))
(MOVE-BP STOP-BP (BP-VALUES BP1))
(VALUES START-BP STOP-BP))
;; looks like neither BP was at the right level
(T
(MOVE-BP START-BP (BOX-SELF-BP-VALUES FIRST-BOX))
(MOVE-BP STOP-BP (BOX-SELF-BP-VALUES LAST-BOX))
(SET-BP-CHA-NO STOP-BP (1+ (BP-CHA-NO STOP-BP)))
(VALUES START-BP STOP-BP))))))
;;;move-point moves the *POINT* BP
(DEFUN MOVE-POINT-1 (NEW-ROW NEW-CHA-NO &OPTIONAL(NEW-SCREEN-BOX NIL))
(UNLESS (NULL NEW-SCREEN-BOX)
(SET-BP-SCREEN-BOX *POINT* NEW-SCREEN-BOX))
(SET-BP-ROW *POINT* NEW-ROW)
(SET-BP-CHA-NO *POINT* NEW-CHA-NO))
(DEFUN MOVE-BP-1 (BP NEW-ROW NEW-CHA-NO &OPTIONAL (NEW-SCREEN-BOX NIL))
(UNLESS (NULL NEW-SCREEN-BOX)
(SET-BP-SCREEN-BOX BP NEW-SCREEN-BOX))
(SET-BP-ROW BP NEW-ROW)
(SET-BP-CHA-NO BP NEW-CHA-NO))
(DEFUN POINT-SCREEN-BOX ()
(BP-SCREEN-BOX *POINT*))
(DEFF BP-COMPUTE-NEW-SCREEN-BOX 'IGNORE)
(DEFUN BP-COMPUTE-NEW-SCREEN-BOX-OUT (OLD-BOX NEW-BOX OLD-SCREEN-BOX)
(LET ((LEVEL (LEVEL-OF-SUPERIORITY NEW-BOX OLD-BOX))
(NEW-SCREEN-BOX OLD-SCREEN-BOX))
(DOTIMES (I LEVEL)
(SETQ NEW-SCREEN-BOX (TELL NEW-SCREEN-BOX :SCREEN-BOX)))
NEW-SCREEN-BOX))
(DEFUN BP-COMPUTE-NEW-SCREEN-BOX-IN (OLD-BOX NEW-BOX OLD-SCREEN-BOX)
(COND ((EQ NEW-BOX OLD-BOX) OLD-SCREEN-BOX)
(T
(TELL NEW-BOX
:ALLOCATE-SCREEN-OBJ-FOR-USE-IN
(BP-COMPUTE-NEW-SCREEN-BOX-IN
OLD-BOX (TELL NEW-BOX :SUPERIOR-BOX) OLD-SCREEN-BOX)))))
(DEFUN VISIBLE-SCREEN-OBJ-OF-INFERIOR-ACTUAL-OBJ (INFERIOR-ACTUAL-OBJ SUPERIOR-SCREEN-OBJ)
(CAR (MEM #'(LAMBDA (SB SR) (TELL SR :SUPERIOR? SB)) SUPERIOR-SCREEN-OBJ
(TELL INFERIOR-ACTUAL-OBJ :DISPLAYED-SCREEN-OBJS))))
(DEFUN LOWEST-VISIBLE-BOX (SUPERIOR-SCREEN-BOX BOXES)
(LOOP FOR N FROM 0 TO (1- (LENGTH BOXES))
FOR BOX = (NTH N BOXES)
FOR SCREEN-BOX = (VISIBLE-SCREEN-OBJ-OF-INFERIOR-ACTUAL-OBJ BOX SUPERIOR-SCREEN-BOX)
WHEN (NULL SCREEN-BOX)
RETURN (WHEN (> N 0) (NTH (1- N) BOXES))
FINALLY (RETURN (CAR (LAST BOXES)))))
(DEFUN BP-FORWARD-CHA-VALUES (BP &OPTIONAL (TIMES 1) (NO-OF-TIMES-TO-COUNT-CRLF 1))
(CHECK-BP-ARG BP)
(BP-FORWARD-CHA-VALUES-1 (BP-ROW BP) (BP-CHA-NO BP) TIMES NO-OF-TIMES-TO-COUNT-CRLF))
(DEFUN BP-FORWARD-CHA-VALUES-1 (OLD-ROW OLD-CHA-NO TIMES NO-OF-TIMES-TO-COUNT-CRLF)
(LET ((OLD-ROW-LENGTH-IN-CHAS (TELL OLD-ROW :LENGTH-IN-CHAS)))
(COND ((<= (+ OLD-CHA-NO TIMES) OLD-ROW-LENGTH-IN-CHAS)
;; The destination is is this row. Our job easy.
(VALUES OLD-ROW (+ OLD-CHA-NO TIMES)))
((NULL (TELL OLD-ROW :NEXT-ROW))
;; The destination isn't in this row, and there
;; is no next row. Just go the the end of this
;; row.
(VALUES OLD-ROW OLD-ROW-LENGTH-IN-CHAS))
(T
;; The destination isn't in this row, and there
;; is a next row to go to. Move the BP to the
;; beginning of the next row and call ourselves
;; recursively.
(BP-FORWARD-CHA-VALUES-1 (TELL OLD-ROW :NEXT-ROW)
0
(- TIMES
(- OLD-ROW-LENGTH-IN-CHAS OLD-CHA-NO)
NO-OF-TIMES-TO-COUNT-CRLF)
NO-OF-TIMES-TO-COUNT-CRLF)))))
(DEFUN BP-BACKWARD-CHA-VALUES (BP &OPTIONAL (TIMES 1) (NO-OF-TIMES-TO-COUNT-CRLF 1))
(CHECK-BP-ARG BP)
(BP-BACKWARD-CHA-VALUES-1 (BP-ROW BP) (BP-CHA-NO BP) TIMES NO-OF-TIMES-TO-COUNT-CRLF))
(DEFUN BP-BACKWARD-CHA-VALUES-1 (OLD-ROW OLD-CHA-NO TIMES NO-OF-TIMES-TO-COUNT-CRLF)
(COND ((<= TIMES OLD-CHA-NO)
;; The destination is in this row. Our job is easy.
(VALUES OLD-ROW (- OLD-CHA-NO TIMES)))
((NULL (TELL OLD-ROW :PREVIOUS-ROW))
;; The destination isn't in this row, and there
;; is no previous row to go to. Just go to the
;; beginning of this row.
(VALUES OLD-ROW 0))
(T
;; The destination isn't in this row, and there
;; is a previous row to go to. Go to the end of
;; the previous row and call ourselves recursivley.
(LET ((OLD-PREVIOUS-ROW (TELL OLD-ROW :PREVIOUS-ROW)))
(BP-BACKWARD-CHA-VALUES-1 OLD-PREVIOUS-ROW
(TELL OLD-PREVIOUS-ROW :LENGTH-IN-CHAS)
(- TIMES
OLD-CHA-NO
NO-OF-TIMES-TO-COUNT-CRLF)
NO-OF-TIMES-TO-COUNT-CRLF)))))
(DEFUN CHA-BP-VALUES (CHA)
(LET ((ROW (TELL CHA :SUPERIOR-ROW)))
(VALUES ROW (TELL ROW :CHA-CHA-NO CHA))))
(DEFUN CHA-NEXT-BP-VALUES (CHA)
(LET ((ROW (TELL CHA :SUPERIOR-ROW)))
(VALUES ROW (+ (TELL ROW :CHA-CHA-NO CHA) 1))))
(DEFUN ROW-FIRST-BP-VALUES (ROW)
(CHECK-ROW-ARG ROW)
(VALUES ROW 0))
(DEFUN ROW-LAST-BP-VALUES (ROW)
(CHECK-ROW-ARG ROW)
(VALUES ROW (TELL ROW :LENGTH-IN-CHAS)))
(DEFUN BOX-FIRST-BP-VALUES (BOX)
(CHECK-BOX-ARG BOX)
(VALUES (TELL BOX :ROW-AT-ROW-NO 0) 0))
;; this handles boxes that may be partially scrolled
(defun box-first-visible-bp-values (box
&optional
(screen-box (car (tell box :displayed-screen-objs))))
(check-box-arg box)
(values (or (and (screen-box? screen-box)
(tell screen-box :scroll-to-actual-row))
(tell box :row-at-row-no 0))
0))
(DEFUN BOX-LAST-BP-VALUES (BOX)
(CHECK-BOX-ARG BOX)
(LET* ((BOX-LENGTH-IN-ROWS (TELL BOX :LENGTH-IN-ROWS))
(LAST-ROW (TELL BOX :ROW-AT-ROW-NO (- BOX-LENGTH-IN-ROWS 1)))
(LAST-ROW-LENGTH-IN-CHAS (TELL LAST-ROW :LENGTH-IN-CHAS)))
(VALUES LAST-ROW LAST-ROW-LENGTH-IN-CHAS)))
(DEFUN BOX-SELF-BP-VALUES (BOX)
(CHECK-BOX-ARG BOX)
(LET ((SUPERIOR-ROW (TELL BOX :SUPERIOR-ROW)))
(VALUES SUPERIOR-ROW (TELL SUPERIOR-ROW :CHA-CHA-NO BOX))))
(DEFUN BP-VALUES (BP)
(CHECK-BP-ARG BP)
(VALUES (BP-ROW BP) (BP-CHA-NO BP) (BP-SCREEN-BOX BP)))
(COMPILER:MAKE-OBSOLETE SET-BP-FROM-BP "Use BP-VALUES with MOVE-BP instead")
;;; Interaction between the editor and the programming environment
;;; Utilities for Prompting, Documentation, Help among other things
;; start from *POINT* and move backwards until we get to a DOIT-BOX. If we are looking at
;; a symbol instead, then return a starting CHA-NO for the symbol in the row.
;; if we run into something obviously NOT a function (like a DATA-BOX) then return NIL
(DEFUN FIND-BOX-OR-SYMBOL-START-NO (BP)
(LET ((ROW (BP-ROW BP)))
(IF (= 0 (BP-CHA-NO BP)) ;BP is at beginning of row
(FIRST-CHA-FUNCTION-OR-START-NO ROW)
(LOOP WITH INSIDE-SYMBOL-P = NIL ;set this flag after any initial whitespace ends
FOR CHA-NO = (1- (BP-CHA-NO BP)) THEN (1- CHA-NO)
FOR CHA = (TELL ROW :CHA-AT-CHA-NO CHA-NO)
UNTIL (AND INSIDE-SYMBOL-P
(MEMQ (CHA-CODE CHA) *FUNCTION-DELIMITERS*))
WHEN (NOT (MEMQ (CHA-CODE CHA) *FUNCTION-DELIMITERS*))
DO (SETQ INSIDE-SYMBOL-P T)
WHEN (DOIT-BOX? CHA)
RETURN CHA
WHEN (= CHA-NO 0)
RETURN CHA-NO
WHEN (DATA-BOX? CHA)
RETURN NIL
WHEN (PORT-BOX? CHA)
RETURN (WHEN (DOIT-BOX? (TELL CHA :PORTS)) (TELL CHA :PORTS))
FINALLY
(RETURN CHA-NO)))))
(DEFUN FIRST-CHA-FUNCTION-OR-START-NO (ROW)
(LET ((FIRST-CHA (TELL ROW :CHA-AT-CHA-NO 0)))
(COND ((DOIT-BOX? FIRST-CHA) FIRST-CHA)
((DATA-BOX? FIRST-CHA) NIL)
((PORT-BOX? FIRST-CHA)
(WHEN (DOIT-BOX? (TELL FIRST-CHA :PORTS)) (TELL FIRST-CHA :PORTS)))
(T 0))))
(DEFUN FIND-SYMBOL-END-NO (BP)
(LOOP WITH ROW = (BP-ROW BP)
FOR CHA-NO = (IF (= 0 (BP-CHA-NO BP)) 0 (1- (BP-CHA-NO BP))) THEN (1+ CHA-NO)
FOR CHA = (TELL ROW :CHA-AT-CHA-NO CHA-NO)
UNTIL (OR (NULL CHA) (MEMQ (CHA-CODE CHA) *FUNCTION-DELIMITERS*))
FINALLY
(RETURN CHA-NO)))
;; If it's not a BOX, then we have to do some work in finding the end point of the symbol
;; remember, we already have the starting point from the function above
(DEFUN FIND-SYMBOL-FROM-START-NO (START-NO BP)
(LET* ((END-NO (FIND-SYMBOL-END-NO BP))
(ROW (BP-ROW BP))
(START-BP (MAKE-INITIALIZED-BP :FIXED ROW START-NO))
(END-BP (MAKE-INITIALIZED-BP :FIXED ROW END-NO))
(STREAM (MAKE-BOXER-STREAM START-BP END-BP))
;;should instead, make editor streams handle :ENTRIES
(STUFF (PARSE-LIST-FOR-EVAL (BOXER-READ STREAM NIL))))
(TELL ROW :DELETE-BP START-BP) ;cleanup time
(TELL ROW :DELETE-BP END-BP)
(WHEN (SYMBOLP (CAR STUFF)) (CAR STUFF))))
(DEFUN FUNCTION-AT-BP (BP)
(LET ((FUNCTION-OR-START-NO (FIND-BOX-OR-SYMBOL-START-NO BP)))
(COND ((NULL FUNCTION-OR-START-NO) NIL)
((DOIT-BOX? FUNCTION-OR-START-NO) FUNCTION-OR-START-NO)
((NUMBERP FUNCTION-OR-START-NO)
(FIND-SYMBOL-FROM-START-NO FUNCTION-OR-START-NO BP))
(T (FERROR "Can't find anything around the BP ~A" BP)))))
(DEFUN FUNCTION-AT-POINT ()
(FUNCTION-AT-BP *POINT*))
;;;;CURSOR-TRACKER
;;Given the fact that there is a variable *POINT* , we can define
;;these simple functions.
(DEFUN POINT-BOX ()
(BP-BOX *POINT*))
(DEFUN POINT-ROW ()
(BP-ROW *POINT*))
(DEFUN POINT-CHA-NO ()
(BP-CHA-NO *POINT*))
(DEFUN POINT-SCREEN-BOX ()
(BP-SCREEN-BOX *POINT*))
(DEFUN SET-POINT-SCREEN-BOX (NEW-SCREEN-BOX)
(SET-BP-SCREEN-BOX *POINT* NEW-SCREEN-BOX))
(DEFUN POINT-CHA-AFTER-POINT ()
(TELL (POINT-ROW) :CHA-AT-CHA-NO (POINT-CHA-NO)))
(DEFF POINT-CHA 'POINT-CHA-AFTER-POINT)
(DEFUN SETUP-EDITOR (&OPTIONAL (LOAD-INIT-FILE-P NIL))
(SETQ *INITIAL-BOX* (MAKE-INITIALIZED-BOX ':TYPE ':DATA-BOX))
(TELL *INITIAL-BOX* :SET-NAME "WORLD")
(SET-OUTERMOST-BOX *INITIAL-BOX*) ;this calls redisplay !
(TELL (CAR (TELL *INITIAL-BOX* :SCREEN-OBJS)) :SET-SCREEN-ROW *BOXER-PANE*)
(TELL (CAR (TELL *INITIAL-BOX* :SCREEN-OBJS))
:SET-SUPERIOR-SCREEN-BOX *BOXER-PANE*)
;; no one seems to use this an it isn't robust enough yet anyway
; (WHEN LOAD-INIT-FILE-P
; (INITIALIZE-BOXER-WORLD))
(SETQ *POINT* (MAKE-BP ':MOVING))
(MULTIPLE-VALUE-BIND (ROW CHA-NO)
(BOX-FIRST-BP-VALUES *INITIAL-BOX*)
(MOVE-POINT-1 ROW CHA-NO (CAR (TELL *INITIAL-BOX* :SCREEN-OBJS)))))
;;;; Support for scrolling (after a c-N from the bottom of a box for example)
;; Estimate the size of a row from the actual structure
;; we are assuming that boxes are ALWAYS bigger than chas
;; this assumes that the font map is already bound
;; it is used by ASSURE-HEAD-ROOM-IN-BOX which bind the font map
(DEFUN ESTIMATE-ROW-HEIGHT (ROW)
(LET ((BOXES (TELL ROW :BOXES-IN-ROW)))
(IF (NULL BOXES)
(LOOP FOR FONT FROM 0 TO (1- (ARRAY-LENGTH %DRAWING-FONT-MAP))
MAXIMIZE (FONT-CHAR-HEIGHT (AREF %DRAWING-FONT-MAP FONT)))
(LOOP FOR BOX IN BOXES
MAXIMIZE (ESTIMATE-BOX-HEIGHT BOX)))))
;; this assumes that the font map is already bound
;; it is used by ASSURE-HEAD-ROOM-IN-BOX which bind the font map
(DEFUN ESTIMATE-BOX-HEIGHT (BOX)
(COND ((EQ (TELL BOX :DISPLAY-STYLE) ':SHRUNK)
27.)
((NUMBERP (CADDR (TELL BOX :DISPLAY-STYLE-LIST)))
(CADDR (TELL BOX :DISPLAY-STYLE-LIST)))
(T
(MULTIPLE-VALUE-BIND (IGNORE TOP IGNORE BOT)
(BOX-BORDERS-FN ':BORDER-WIDS (TELL BOX :TYPE) NIL)
(+ TOP BOT (LOOP FOR ROW IN (TELL BOX :ROWS)
SUMMING (ESTIMATE-ROW-HEIGHT ROW)))))))
(DEFUN ASSURE-HEAD-ROOM-IN-BOX (LAST-ROW SCREEN-BOX &OPTIONAL (WINDOW *BOXER-PANE*))
"This starts at LAST-ROW and returns the highest up row that can be the 1st row and still
have LAST-ROW be displayed based on the current size of SCREEN-BOX. "
(WITH-FONT-MAP-BOUND (WINDOW)
(LET ((AVAILABLE-ROOM (MULTIPLE-VALUE-BIND (IGNORE TOP IGNORE BOT)
(BOX-BORDERS-FN ':BORDER-WIDS
(TELL (TELL SCREEN-BOX :ACTUAL-OBJ) :TYPE)
NIL)
(- (TELL SCREEN-BOX :HEI) TOP BOT))))
(LOOP FOR ROW = LAST-ROW THEN (TELL ROW :PREVIOUS-ROW)
FOR ROOM = (- AVAILABLE-ROOM (ESTIMATE-ROW-HEIGHT ROW))
THEN (- ROOM (ESTIMATE-ROW-HEIGHT ROW))
WHEN (NULL ROW)
RETURN (TELL (TELL LAST-ROW :SUPERIOR-BOX) :FIRST-INFERIOR-ROW)
UNTIL ( ROOM 0)
FINALLY
(RETURN ROW)))))
(DEFUN ASSURE-LEG-ROOM-IN-BOX (ROW SCREEN-BOX)
SCREEN-BOX ;bound but never used...
ROW)
;; does the row have screen structure within the screen box
(DEFMETHOD (ROW :ROW-HAS-SCREEN-STRUCTURE?)(&OPTIONAL (CURRENT-SCREEN-BOX (POINT-SCREEN-BOX)))
(CDR (ASSQ CURRENT-SCREEN-BOX SCREEN-OBJS)))
(DEFUN ENSURE-ROW-IS-DISPLAYED (ROW SCREEN-BOX &OPTIONAL (DIRECTION -1) SCROLL-ANYWAY)
"Make sure that the screen box's scroll to actual row is such that ROW will be seen.
a DIRECTION of 1 specifies that we are moving downward, -1 upward. "
(WHEN (OR SCROLL-ANYWAY
(NULL (TELL ROW :ROW-HAS-SCREEN-STRUCTURE? SCREEN-BOX))
(TELL (TELL ROW :ALLOCATE-SCREEN-OBJ-FOR-USE-IN SCREEN-BOX) :Y-GOT-CLIPPED?))
(TELL SCREEN-BOX :SET-SCROLL-TO-ACTUAL-ROW (IF (MINUSP DIRECTION)
(ASSURE-HEAD-ROOM-IN-BOX ROW SCREEN-BOX)
;; sounds like a box is a luxury car
(ASSURE-LEG-ROOM-IN-BOX ROW SCREEN-BOX)))))
;;;; Input Boxes
;;; input boxes usurp the point and recursively call the boxer editing command loop
;;; when the desired configuration of the input box is achieved, then the USER exits
;;; the box at which point the recursive command loop is THROWN out of and the desired value
;;; is CATCHed
;;; this will have to be moved elsewhere. Also, is there any situation in which we would need
;;; a REAL box to be created....
(DEFUN PARSE-SELF-FOR-INPUT (BOX)
"Make a Evdata Box from an input box without the prompt string. "
(LOOP FOR ROW IN (GET-BOX-ROWS BOX)
UNLESS (NULL ROW)
COLLECT (MAKE-EVROW-FROM-ENTRIES ROW) INTO RETURN-ROWS
FINALLY (RETURN (MAKE-EVDATA ROWS RETURN-ROWS))))
(DEFMETHOD (INPUT-BOX :AFTER :EXIT) (&REST IGNORE)
;; return out of the inferior command-loop
(*THROW 'BOXER-IO (PARSE-SELF-FOR-INPUT SELF)))
(DEFUN MAKE-INPUT-BOX (PROMPT)
(COND ((NULL PROMPT) (MAKE-BOX '(()) 'INPUT-BOX))
((EVAL-BOX? PROMPT)
(LET ((BOX (MAKE-BOX (NCONS (LIST ";" PROMPT)) 'INPUT-BOX)))
(TELL BOX :APPEND-ROW (MAKE-ROW '()))
BOX))
((LISTP PROMPT)
(LET ((BOX (MAKE-BOX (NCONS (APPEND '(";") PROMPT)) ':INPUT-BOX)))
(TELL BOX :APPEND-ROW (MAKE-ROW '()))
BOX))
((STRINGP PROMPT)
(LET ((BOX (MAKE-BOX (NCONS (LIST ";" PROMPT)) ':INPUT-BOX)))
(TELL BOX :APPEND-ROW (MAKE-ROW '()))
BOX))
(T (FERROR "Don't know how to make an input box from ~A" PROMPT))))
(DEFUN GET-BOXER-INPUT (PROMPT)
(LET ((INPUT-BOX (MAKE-INPUT-BOX PROMPT)))
(UNWIND-PROTECT
(*CATCH 'BOXER-IO
(INSERT-CHA *POINT* INPUT-BOX)
(REDISPLAY)
(MOVE-POINT (BOX-LAST-BP-VALUES INPUT-BOX))
(SET-POINT-SCREEN-BOX (CAR (TELL INPUT-BOX :SCREEN-OBJS)))
(MINI-BOXER-COMMAND-LOOP))
(WHEN (TELL (POINT-BOX) :SUPERIOR? INPUT-BOX)
;; if we are inside the input box when an ABORT hits...
;; we'd better get rid of it
(SET-POINT-SCREEN-BOX (BP-COMPUTE-NEW-SCREEN-BOX-OUT (POINT-BOX)
(TELL INPUT-BOX :SUPERIOR-BOX)
(POINT-SCREEN-BOX)))
(MOVE-POINT (BOX-SELF-BP-VALUES INPUT-BOX))
(TELL (TELL INPUT-BOX :SUPERIOR-ROW) :DELETE-CHA INPUT-BOX)))))
;;;; The Boxer Status Line
;;; We are currently using ONE line of the *NAME-PANE*. In the future, we might want to
;;; expand this to several lines and make it like an EMACS typein window
(DEFUN GET-BOXER-VERSION-STRING ()
"Special versions of BOXER are indicated by SETQing *BOXER-VERSION-INFO*
to a descriptive string. Otherwise, the release status, major and minor version numbers
of the currently loaded system are used. "
(MULTIPLE-VALUE-BIND (MAJOR MINOR STATUS)
(SI:GET-SYSTEM-VERSION "Boxer")
(IF (NULL *BOXER-VERSION-INFO*)
(FORMAT NIL "~A BOXER ~D.~D" STATUS MAJOR MINOR)
*BOXER-VERSION-INFO*)))
(DEFUN GET-BOXER-STATUS-STRING (&OPTIONAL (OUTERMOST-BOX-NAME (TELL (OUTERMOST-BOX) :NAME)))
(IF (NULL *EDITOR-NUMERIC-ARGUMENT*)
(FORMAT NIL "~A | Outermost Box: ~A" (GET-BOXER-VERSION-STRING) OUTERMOST-BOX-NAME)
(FORMAT NIL "~A | Outermost Box: ~A | Arg: ~D" (GET-BOXER-VERSION-STRING)
OUTERMOST-BOX-NAME
*EDITOR-NUMERIC-ARGUMENT*)))
(DEFUN REQUIRED-STATUS-LINE-LENGTH (&OPTIONAL (OUTERMOST-BOX-NAME
(TELL (OUTERMOST-BOX) :NAME)))
(TELL *NAME-PANE* :STRING-LENGTH (FORMAT NIL "~A | Outermost Box: ~A"
(GET-BOXER-VERSION-STRING)
OUTERMOST-BOX-NAME)))
(DEFUN REDRAW-STATUS-LINE (&OPTIONAL NEW-NAME)
(COND ((NULL NEW-NAME)
(TELL *NAME-PANE* :SET-CURSORPOS (REQUIRED-STATUS-LINE-LENGTH) 0)
(TELL *NAME-PANE* #+SYMBOLICS :CLEAR-REST-OF-LINE #-SYMBOLICS :CLEAR-EOL)
(UNLESS (NULL *EDITOR-NUMERIC-ARGUMENT*)
(TELL *NAME-PANE* :STRING-OUT
(FORMAT NIL " | Arg: ~D" *EDITOR-NUMERIC-ARGUMENT*))))
(T (TELL *NAME-PANE* #+SYMBOLICS :CLEAR-WINDOW #-SYMBOLICS :CLEAR-SCREEN)
(TELL *NAME-PANE* :STRING-OUT (GET-BOXER-STATUS-STRING NEW-NAME)))))
(COMMENT
(DEFVAR *HISTORY-LIST* NIL)
(DEFUN HISTORY-RECORD-USER-ENTERED-BOX (BOX)
(HISTORY-LIST-ADD-BOX-TO-HISTORY BOX))
(DEFUN HISTORY-LIST-ADD-BOX-TO-HISTORY (BOX)
(PUSH BOX *HISTORY-LIST*))
(DEFUN HISTORY-RECORD-USER-CHANGED-OUTERMOST-BOX (OLD-OUTERMOST-BOX)
(HISTORY-PANE-ADD-BOX-TO-HISTORY OLD-OUTERMOST-BOX))
(DEFVAR *HISTORY-PANE-NO-OF-HISTORY-PORTS* 5.)
(DEFUN SETUP-HISTORY-PANE ()
(LET* ((NEW-BOX (MAKE-INITIALIZED-BOX ':TYPE ':DATA-BOX))
(NEW-SCREEN-BOX (TELL NEW-BOX :ALLOCATE-SCREEN-OBJ-FOR-USE-IN
*HISTORY-PANE*)))
(SET-OUTERMOST-BOX NEW-BOX NEW-SCREEN-BOX *HISTORY-PANE*)))
(DEFUN HISTORY-PANE-SCREEN-BOX ()
(TELL *HISTORY-PANE* :OUTERMOST-SCREEN-BOX))
(DEFUN HISTORY-PANE-SCREEN-ROW ()
(TELL (HISTORY-PANE-SCREEN-BOX) :FIRST-SCREEN-ROW))
(DEFUN HISTORY-PANE-BOX ()
(SCREEN-OBJ-ACTUAL-OBJ (HISTORY-PANE-SCREEN-BOX)))
(DEFUN HISTORY-PANE-ROW ()
(SCREEN-OBJ-ACTUAL-OBJ (HISTORY-PANE-SCREEN-ROW)))
(DEFUN HISTORY-PANE-SCREEN-HISTORY-PORT-BOX-SIZE ()
(REDISPLAYING-WINDOW (*HISTORY-PANE*)
(MULTIPLE-VALUE-BIND (IL IT IR IB)
(BOX-BORDERS-FN ':BORDER-WIDS ':PORT-BOX)
(LET ((INSIDE-WID (- (SCREEN-OBJ-WID (HISTORY-PANE-SCREEN-BOX)) IL IR))
(INSIDE-HEI (- (SCREEN-OBJ-HEI (HISTORY-PANE-SCREEN-BOX)) IT IB)))
(VALUES (// INSIDE-WID (+ *HISTORY-PANE-NO-OF-HISTORY-PORTS* 1))
INSIDE-HEI)))))
(DEFUN HISTORY-PANE-ADD-BOX-TO-HISTORY (BOX)
(LET ((PORT-BOX (MAKE-INITIALIZED-BOX ':TYPE ':PORT-BOX)))
(TELL PORT-BOX :SET-PORT-TO-BOX BOX)
(IF (>= (TELL (HISTORY-PANE-ROW) :LENGTH-IN-CHAS)
*HISTORY-PANE-NO-OF-HISTORY-PORTS*)
(TELL (HISTORY-PANE-ROW) :DELETE-CHA-AT-CHA-NO 0))
(TELL (HISTORY-PANE-ROW) :APPEND-CHA PORT-BOX)
(MULTIPLE-VALUE-BIND (SCREEN-PORT-BOX-WID SCREEN-PORT-BOX-HEI)
(HISTORY-PANE-SCREEN-HISTORY-PORT-BOX-SIZE)
(LET ((SCREEN-PORT-BOX
(TELL PORT-BOX :ALLOCATE-SCREEN-OBJ-FOR-USE-IN (HISTORY-PANE-SCREEN-BOX))))
(TELL SCREEN-PORT-BOX :SET-DISPLAY-STYLE
(CONS SCREEN-PORT-BOX-WID SCREEN-PORT-BOX-HEI))))))
)